﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE80;
using EnvDTE;
using System.IO;

namespace Raona.Code.Inspection
{
    /// <summary>
    /// Helper class to deal with Visual Studio solution and project structure
    /// </summary>
    public class ProjectInspector
    {
        #region Instance Constructors (Public)

        /// <summary>
        /// The VS root object
        /// </summary>
        private DTE2 applicationObject = null;

        #endregion

        #region Instance Constructors (Public)

        /// <summary>
        /// Initializing constructor
        /// </summary>
        /// <param name="applicationObject"></param>
        public ProjectInspector(DTE2 applicationObject)
        {
            if (applicationObject != null)
                this.applicationObject = applicationObject;
            else
                throw new ArgumentNullException("applicationObject");
        }

        #endregion

        #region Instance Properties (Public)
         
        #endregion
    
        #region Instance Methods (Public)

        /// <summary>
        /// Returns the project with the specified name
        /// </summary>
        /// <param name="projectName"></param>
        /// <returns></returns>
        public Project FindProject(string projectName)
        {
            Project project = null;
            Projects projects = this.applicationObject.Solution.Projects;
            int count = projects.Count;
            bool found = false;
            for (int i = 1; i <= count && !found; i++)
            {
                Project solutionProject = projects.Item(i);
                if (solutionProject.Name == projectName)
                {
                    project = solutionProject;
                    //Configuration conf = project.ConfigurationManager.ActiveConfiguration;
                    //Properties props = conf.Properties;
                    //System.Collections.IEnumerator en = props.GetEnumerator();
                    //while (en.MoveNext())
                    //{
                    //    Property p = en.Current as Property;
                    //    System.Diagnostics.Debug.WriteLine(p.Name);
                    //    if (p.Name == "OutputPath")
                    //        System.Diagnostics.Debug.WriteLine(p.Value as string);

                    //}
                    //System.Diagnostics.Debug.WriteLine("=====");

                    //props = project.Properties;
                    //en = props.GetEnumerator();
                    //while (en.MoveNext())
                    //{
                    //    Property p = en.Current as Property;
                    //    System.Diagnostics.Debug.WriteLine(p.Name);
                    //    if (p.Name == "OutputFileName")
                    //        System.Diagnostics.Debug.WriteLine(p.Value as string);

                    //}

                    //int n = props.Count;
                }
                else if (solutionProject.Kind == EnvDTEConstants.vsProjectKindSolutionItems)
                {
                    project = this.FindProject(projectName, solutionProject.ProjectItems);
                }
                found = project != null;
            }
            return project;
        }

        /// <summary>
        /// Adds a file to the specified project
        /// </summary>
        /// <param name="project"></param>
        /// <param name="filePath"></param>
        public void AddFileToProject(Project project, string filePath)
        {
            string fileName = Path.GetFileName(filePath);
            string projectFilePath = Path.Combine(Path.GetDirectoryName(project.FullName), fileName);
            File.Copy(filePath, projectFilePath, true);
            if (!this.IsItemInProject(project, fileName))
                project.ProjectItems.AddFromFile(projectFilePath);
        }

        /// <summary>
        /// Returns true if the an item is in the specified project
        /// </summary>
        /// <param name="destinationProject"></param>
        /// <param name="itemName"></param>
        /// <returns></returns>
        public bool IsItemInProject(Project destinationProject, string itemName)
        {
            bool itemFound = false;
            ProjectItems projectItems = destinationProject.ProjectItems;
            int itemCount = projectItems.Count;
            for (int i = 1; i <= itemCount && !itemFound; i++)
            {
                itemFound = projectItems.Item(i).Name == itemName;
            }
            return itemFound;
        }

        /// <summary>
        /// Returns the names of all the projects in the solution
        /// </summary>
        /// <returns></returns>
        public List<string> GetSolutionProjects()
        {
            List<string> projectNames = new List<string>();

            Projects projects = this.applicationObject.Solution.Projects;
            int count = projects.Count;
            for (int i = 1; i <= count; i++)
            {
                Project solutionProject = projects.Item(i);
                if (solutionProject.Kind == EnvDTEConstants.vsProjectKindSolutionItems)
                {
                    this.GetSolutionProjects(projectNames, solutionProject.ProjectItems);
                }
                else
                {
                    projectNames.Add(solutionProject.Name);
                }
            }

            return projectNames;
        }

        public bool HasOutputFile(string projectName)
        {
            bool hasOutputFile = false;

            Project project = this.FindProject(projectName);
            if (project != null)
            {
                Configuration conf = project.ConfigurationManager.ActiveConfiguration;
                Properties props = conf.Properties;
                Property outputPathProperty = props.Item("OutputPath");
                Property outputFileProperty = project.Properties.Item("OutputFileName");
                if (outputPathProperty != null && outputFileProperty != null)
                {
                    string path = Path.Combine(Path.GetDirectoryName(project.FullName), outputPathProperty.Value as string);
                    path = Path.Combine(path, outputFileProperty.Value as string);
                    hasOutputFile = File.Exists(path);
                }
            }

            return hasOutputFile;
        }

        #endregion

        #region Instance Methods (Private)

        private Project FindProject(string projectName, ProjectItems projectItems)
        {
            Project project = null;
            bool found = false;
            int count = projectItems.Count;
            for (int i = 1; i <= count && !found; i++)
            {
                ProjectItem projectItem = projectItems.Item(i);
                if (projectItem.Kind == EnvDTEConstants.vsProjectKindSolutionItems)
                {
                    project = this.FindProject(projectName, projectItem.ProjectItems);
                }
                else if (projectItem.Kind == EnvDTEConstants.vsProjectItemKindSolutionItems)
                {
                    if (projectItem.Name == projectName)
                    {
                        found = true;
                        project = (Project)projectItem.Object;
                    }
                }
            }
            return project;
        }

        private void GetSolutionProjects(List<string> projectNames, ProjectItems projectItems)
        {
            if (projectItems != null)
            {
                int count = projectItems.Count;
                for (int i = 1; i <= count; i++)
                {
                    ProjectItem projectItem = projectItems.Item(i);
                    if (projectItem.Kind == EnvDTEConstants.vsProjectKindSolutionItems ||
                        (projectItem.Kind == EnvDTEConstants.vsProjectItemKindSolutionItems 
                            && projectItem.SubProject != null
                            && string.IsNullOrEmpty(projectItem.SubProject.FileName)))
                    {
                        this.GetSolutionProjects(projectNames, projectItem.ProjectItems);
                    }
                    else
                    {
                        projectNames.Add(projectItem.Name);
                    }
                }
            }
        }

        #endregion
    }
}
